package com.ruoyi.process.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.flowable.common.constant.ProcessConstants;
import com.ruoyi.flowable.common.enums.FlowComment;
import com.ruoyi.flowable.domain.dto.FlowTaskDto;
import com.ruoyi.flowable.domain.dto.FlowViewerDto;
import com.ruoyi.flowable.factory.FlowServiceFactory;
import com.ruoyi.flowable.service.IFlowDefinitionService;
import com.ruoyi.flowable.service.IFlowTaskService;
import com.ruoyi.process.dao.DeviceRepairDao;
import com.ruoyi.process.dao.DeviceRepairDetailDao;
import com.ruoyi.process.dao.DeviceRepairFilesDao;
import com.ruoyi.process.entity.DeviceRepair;
import com.ruoyi.process.entity.DeviceRepairFiles;
import com.ruoyi.process.service.DeviceRepairService;
import com.ruoyi.system.service.ISysUserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Description:
 * @ProjectName: ruoyi
 * @Package: com.walker.process.service.impl
 * @ClassName: DeviceRepairServiceImpl
 * @Author: yangyl
 * @CreateDate: 2022/4/23 23:12
 */
@Service
public class DeviceRepairServiceImpl extends FlowServiceFactory implements DeviceRepairService {

    private static final Logger logger = LoggerFactory.getLogger(DeviceRepairServiceImpl.class);

    @Autowired
    private DeviceRepairDao deviceRepairDao;
    @Autowired
    private DeviceRepairDetailDao deviceRepairDetailDao;
    @Autowired
    private DeviceRepairFilesDao deviceRepairFilesDao;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IFlowDefinitionService flowDefinitionService;
    @Autowired
    private IFlowTaskService flowTaskService;

    private Map<String, String> processKeyMap = new HashMap<>();
    public static final String DEVICE_REPAIR_KEY = "process_device_repair";
    private static final String PROCESS_DEF_KEY = "procDefKey";

    public DeviceRepairServiceImpl() {
        processKeyMap.put(DEVICE_REPAIR_KEY, "process_device_repair:5:aa59a24f-db6a-11ec-b923-005056c00008");
    }

    /**
     * @param params
     * @return
     */
    @Override
    @Transactional
    public AjaxResult apply(Map<String, Object> params) {
        String processKey = MapUtils.getString(params, PROCESS_DEF_KEY);
        if (StringUtils.isEmpty(processKey)) {
            AjaxResult paramError = AjaxResult.error(HttpStatus.BAD_REQUEST, "参数错误");
            return paramError;
        }
        String procDefId = MapUtils.getString(processKeyMap, processKey);
        AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById(procDefId, params);
        if (!ajaxResult.execSuccess()) return ajaxResult;
        String processInstanceId = MapUtils.getString(ajaxResult, "processInstanceId");
        //设备维修
        addDeviceRepair(params, processInstanceId);
        return ajaxResult;
    }

    private void addDeviceRepair(Map<String, Object> params, String processInstanceId) {
        String processKey = MapUtils.getString(params, PROCESS_DEF_KEY);
        if (!StringUtils.equalsIgnoreCase(DEVICE_REPAIR_KEY, processKey)) {
            return;
        }
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        DeviceRepair deviceRepair = new DeviceRepair();
        deviceRepair.setPkId(IdUtils.fastSimpleUUID());
        deviceRepair.setProcInstanceId(processInstanceId);
        deviceRepair.setRepairNo("");

        String name = MapUtils.getString(params, "name", "");
        String type = MapUtils.getString(params, "type", "");
        String remark = MapUtils.getString(params, "remark", "");
        deviceRepair.setName(name);
        deviceRepair.setType(type);
        deviceRepair.setRemark(remark);

        deviceRepair.setCreateUserId(String.valueOf(sysUser.getUserId()));
        deviceRepair.setCreateTime(new Date());
        deviceRepair.setCreateUser(sysUser.getUserName());

        deviceRepairDao.insertSelective(deviceRepair);

        //文件处理
        List<Map> fileList = (List<Map>) MapUtils.getObject(params, "fileList");
        addDeviceFiles(fileList, deviceRepair.getPkId(), String.valueOf(sysUser.getUserId()), sysUser.getUserName());
    }

    private void addDeviceFiles(List<Map> fileList, String repairId, String userId, String userName) {
        if (CollectionUtils.isEmpty(fileList)) return;
        List<DeviceRepairFiles> deviceFiles = new ArrayList<>();
        for (Map map : fileList) {
            String fileName = MapUtils.getString(map, "fileName");
            String url = MapUtils.getString(map, "url");
            if (StringUtils.isAnyBlank(fileName, url)) continue;
            DeviceRepairFiles deviceFile = new DeviceRepairFiles();
            deviceFile.setPkId(IdUtils.fastSimpleUUID());
            deviceFile.setRepairId(repairId);
            deviceFile.setUrl(url);
            deviceFile.setFileName(fileName);
            deviceFile.setCreateTime(new Date());
            deviceFile.setCreateUser(userName);
            deviceFile.setCreateUserId(userId);
            deviceFile.setDelFlag(1);
            deviceFiles.add(deviceFile);
        }
        if (CollectionUtils.isNotEmpty(deviceFiles)) {
            deviceRepairFilesDao.insertFilesSelective(deviceFiles);
        }
    }

    @Override
    public AjaxResult todoList(Integer pageNum, Integer pageSize) {
        Page<FlowTaskDto> page = new Page<>();
        //todo 待修改
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
//        SysUser sysUser = new SysUser();
//        sysUser.setUserId(119l);
//        sysUser.setRoleId(102l);

        Long userId = sysUser.getUserId();
        Long[] roleIds = sysUser.getRoleIds();
        Long roleId = sysUser.getRoleId();
        List<String> roleIdList = new ArrayList<>();
        if (roleIds != null && roleIds.length > 0)
            for (Long roleIdTmp : roleIds) {
                roleIdList.add(String.valueOf(roleIdTmp));
            }
        if (roleId != null) {
            roleIdList.add(String.valueOf(roleId));
        }

        TaskQuery taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables();
        taskQuery.taskCandidateOrAssigned(String.valueOf(userId));  //人员查询
        if (CollectionUtils.isNotEmpty(roleIdList)) {  //角色查询
            taskQuery.taskCandidateGroupIn(roleIdList);
        }
        taskQuery.orderByTaskCreateTime().desc();
        page.setTotal(taskQuery.count());
        List<Task> taskList = taskQuery.listPage(pageSize * (pageNum - 1), pageSize);
        if (CollectionUtils.isEmpty(taskList)) {  //按人员查
            taskQuery.taskAssignee(String.valueOf(userId));
            taskList = taskQuery.listPage(pageSize * (pageNum - 1), pageSize);
        }
        List<FlowTaskDto> flowList = new ArrayList<>();
        for (Task task : taskList) {
            FlowTaskDto flowTask = new FlowTaskDto();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId())
                    .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcDefKey(pd.getKey());
            flowTask.setProcInsId(task.getProcessInstanceId());

            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .singleResult();
            String startUserId = historicProcessInstance.getStartUserId();
            if (StringUtils.isNotEmpty(startUserId)) {
                SysUser startUser = sysUserService.selectUserById(Long.parseLong(startUserId));
                if (startUser != null) {
                    flowTask.setStartUserId(String.valueOf(startUser.getUserId()));
                    flowTask.setStartUserName(startUser.getNickName());
                    flowTask.setStartDeptName(startUser.getDept().getDeptName());
                }
            }

            flowTask.setProcVars(task.getProcessVariables());  //公共变量
            flowList.add(flowTask);
        }

        page.setRecords(flowList);
        return AjaxResult.success(page);
    }

    @Override
    public AjaxResult todoCount() {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        Long userId = sysUser.getUserId();
        Long[] roleIds = sysUser.getRoleIds();
        Long roleId = sysUser.getRoleId();
        List<String> roleIdList = new ArrayList<>();
        if (roleIds != null && roleIds.length > 0)
            for (Long roleIdTmp : roleIds) {
                roleIdList.add(String.valueOf(roleIdTmp));
            }
        if (roleId != null) {
            roleIdList.add(String.valueOf(roleId));
        }

        TaskQuery taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables();
        taskQuery.taskCandidateOrAssigned(String.valueOf(userId));  //人员查询
        if (CollectionUtils.isNotEmpty(roleIdList)) {  //角色查询
            taskQuery.taskCandidateGroupIn(roleIdList);
        }
        taskQuery.orderByTaskCreateTime().desc();
        long todoCount = taskQuery.count();
        if (todoCount <= 0) {  //按人员查
            taskQuery.taskAssignee(String.valueOf(userId));
            todoCount = taskQuery.count();
        }
        Map<String,Object> resultMap=new HashMap<>(2);
        resultMap.put("todoCount",todoCount);
        return  AjaxResult.success(resultMap);
    }

    @Override
    @Transactional
    public AjaxResult completeTask(Map<String, Object> params) {
        String taskId = MapUtils.getString(params, "taskId");
        String comment = MapUtils.getString(params, "comment", "");
        int status = MapUtils.getIntValue(params, "status", 0);
        String processKey = MapUtils.getString(params, PROCESS_DEF_KEY);
        AjaxResult paramError = AjaxResult.error(HttpStatus.BAD_REQUEST, "参数错误");
        if (StringUtils.isBlank(taskId) || StringUtils.isEmpty(processKey)) return paramError;

        List<Integer> statuses = Arrays.asList(1, 2); //状态允许值
        if (status <= 0 || !statuses.contains(status)) {
            return paramError;
        }
        //todo 待修改
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
//        SysUser sysUser = new SysUser();
//        sysUser.setUserId(118l);
//        sysUser.setUserName("某某");
        String userId = String.valueOf(sysUser.getUserId());
        String userName = String.valueOf(sysUser.getUserName());

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            return AjaxResult.error("任务不存在");
        }
        //设备维修临时表
        completeDeviceRepair(params, task, status, userId, userName);
        Map<String, Object> transientVariables = new HashMap<>(2);
        transientVariables.put("status", status);
        //支持流程发起人
        transientVariables.put(ProcessConstants.PROCESS_INITIATOR, MapUtils.getString(params, ProcessConstants.PROCESS_INITIATOR));
        List<Map> fileList = (List<Map>) MapUtils.getObject(params, "fileList");
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.addComment(taskId, task.getProcessInstanceId(), FlowComment.DELEGATE.getType(), comment);
            taskService.resolveTask(taskId, null, transientVariables);
        } else {
            taskService.addComment(taskId, task.getProcessInstanceId(), FlowComment.NORMAL.getType(), comment);
            taskService.setAssignee(taskId, userId);
            taskService.complete(taskId, null, transientVariables);
        }

        //文件处理
        Map<String, Object> repairMap = new HashMap<>(1);
        repairMap.put("procInstanceId", task.getProcessInstanceId());
        DeviceRepair deviceRepairDb = deviceRepairDao.getDeviceRepair(repairMap);
        if (deviceRepairDb != null) {
            addDeviceFiles(fileList, deviceRepairDb.getPkId(), String.valueOf(sysUser.getUserId()), sysUser.getUserName());
        }
        return AjaxResult.success();
    }

    private void completeDeviceRepair(Map<String, Object> params, Task task, Integer status, String userId, String userName) {
        String processKey = MapUtils.getString(params, PROCESS_DEF_KEY);
        String comment = MapUtils.getString(params, "comment", ""); //备注字段
        if (!StringUtils.equalsIgnoreCase(DEVICE_REPAIR_KEY, processKey)) {
            return;
        }

        Map<String, Object> repairMap = new HashMap<>(1);
        repairMap.put("procInstanceId", task.getProcessInstanceId());
        DeviceRepair deviceRepairDb = deviceRepairDao.getDeviceRepair(repairMap);
        //判断状态及备注字段
        String taskDefinitionKey = task.getTaskDefinitionKey();
        logger.info("---->:{}", taskDefinitionKey);
        DeviceRepair deviceRepairUpdate = new DeviceRepair();

        params.put(ProcessConstants.PROCESS_INITIATOR, deviceRepairDb.getCreateUserId());
        deviceRepairUpdate.setPkId(deviceRepairDb.getPkId());
        if (taskDefinitionKey.endsWith("approve")) {
            deviceRepairUpdate.setStatus(status);
            deviceRepairUpdate.setApproveId(userId);
            deviceRepairUpdate.setApproveName(userName);
            deviceRepairUpdate.setApproveTime(new Date());
            deviceRepairUpdate.setApproveRemark(comment);
        } else if (taskDefinitionKey.endsWith("resolve")) {
            deviceRepairUpdate.setResolveStatus(status);
            deviceRepairUpdate.setResolveUserId(userId);
            deviceRepairUpdate.setResolveUser(userName);
            deviceRepairUpdate.setResolveTime(new Date());
            deviceRepairUpdate.setResolveRemark(comment);
        } else if (taskDefinitionKey.endsWith("check")) {
            deviceRepairUpdate.setCheckStatus(status);
            deviceRepairUpdate.setCheckTime(new Date());
            deviceRepairUpdate.setCheckRemark(comment);
        } else {
            return;
        }
        deviceRepairUpdate.setPkId(deviceRepairDb.getPkId());  //db主键
        //修改维修表
        deviceRepairDao.updateByPrimaryKeySelective(deviceRepairUpdate);
    }

    @Override
    public AjaxResult flowRecord(String procInsId) {
        AjaxResult ajaxResult = flowTaskService.flowRecord(procInsId, null);
        List<FlowViewerDto> userTasks = flowTaskService.getUserTasks(procInsId);
        ajaxResult.put("userTaskList",userTasks);
        String step="";
        for (int i = 0; i < userTasks.size(); i++) {
            FlowViewerDto userTask=userTasks.get(i);
            FlowViewerDto prevUserTask=i>0?userTasks.get(i-1):null;
            if(!userTask.isCompleted() && prevUserTask.isCompleted()
                    && StringUtils.contains(userTask.getKey(),"resolve")){
                step="3";  //执行
            }
            if(!userTask.isCompleted() && prevUserTask.isCompleted()
                    && StringUtils.contains(userTask.getKey(),"check")){
                step="4";  //验收
            }
        }
        ajaxResult.put("step",step);
        return ajaxResult;
    }


    @Override
    public AjaxResult finishTaskList(Integer pageNum, Integer pageSize) {
        AjaxResult ajaxResult = flowTaskService.myProcess(pageNum, pageSize);
        return ajaxResult;
    }

    @Override
    public AjaxResult finishTaskList(Integer pageNum, Integer pageSize, Map<String, Object> otherMap) {
        AjaxResult ajaxResult = flowTaskService.myProcess(pageNum, pageSize,otherMap);
        return ajaxResult;
    }
}
